# -*- coding:utf-8 -*-
import traceback
import re
import os
from time import sleep
from selenium.common import exceptions as SeleniumExceptions
from selenium.webdriver.common.by import By
from qturboframe.lib.webdriver.remote.webelement import WebElement
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.lib.webdriver.data_change import (deal_inputdata, get_same_value_in_lists,
                                         deal_datetime, deal_time)
# from hslib.CommonScripts import logger
from qturboframe.lib.report.log import logger
from qturboframe.lib.utils.variable import Variable
from qturboframe.public_ui.bui import PublicUI, BaseElement


class BUI(PublicUI):
    '''
    class for bui
    '''

    def wait_page_loading(self, timeout=30):
        timeout_active = 3
        timeout1 = 0
        timeout2 = 0
        if timeout > timeout_active:
            while timeout1 < timeout_active:
                body_class = self.driver.find_element_by_attribute(
                    'css selector', 'body', timeout=1).get_attribute('class')
                if body_class == 'hs-ui-load-page':
                    break
                else:
                    timeout1 += 1
                    sleep(1)
        while timeout2 < (timeout - timeout_active):
            body_class = self.driver.find_element_by_attribute(
                'css selector', 'body', timeout=1).get_attribute('class')
            if body_class == 'hs-ui-load-page':
                timeout1 += 1
                sleep(1)
            else:
                break

    def button(self, idname, text=None, father=None):
        '''
        获取bui的按钮对象

        :Args:
         - timeout: 超时时间


        :Example:
        '''
        if not father:
            father = self.driver

        return Button(idname, father, self.timeout)

    def menu(self, idname=None):
        '''
        bui的菜单栏对象

        :Args:
         - idname: 菜单栏的定位条件，字典类型：{'元素查找方式':'元素查找语句', '辅助属性':'辅助属性值'}

        :Return:
            返回Menu对象

        :Example:
         - 例1: menu = FrontEnd(driver).menu()
         - 例2: menu = FrontEnd(driver).menu({By.ID:'id'})
        '''

        if idname:
            menu = Menu(idname, self.driver, self.timeout)
        else:
            menu = Menu({"css selector": "div.sys-menu-lists"}, self.driver, self.timeout)
        return menu

    def frame(self):
        '''
        bui的frame对象

        :Return:
            返回Frame对象

        :Example:
         - 例1: menu = FrontEnd(driver).frame()
        '''
        return Frame(self.driver)

    # Test_add
    def pop_window(self):
        '''
        bui 弹出窗口

        :Return:
            返回PopWindow对象

        :Example:
         - 例1: menu = FrontEnd(driver).pop_window()
        '''
        return PopWindow(self.driver, self.timeout)

    # Test_add
    def table(self):
        '''
        bui 弹出窗口

        :Return:
            返回PopWindow对象

        :Example:
         - 例1: menu = FrontEnd(driver).pop_window()
        '''

        return Table(self.driver, self.timeout)
    
    def select(self, element_para, father=None):
        '''
        bui 下拉菜单

        :Return:
            返回Select对象

        :Example:
         - 例1: menu = FrontEnd(driver).select()
        '''
        if father is None:
            father = self.driver

        return Select(element_para, father, self.timeout)

    def form(self, idname, father=None):
        '''
        bui Form表单操作

        :Return:
            返回Select对象

        :Example:
         - 例1: menu = FrontEnd(driver).select()
        '''
        if father is None:
            father = self.driver

        if idname:
            return Form(idname, father, self.timeout)

        return Form({"css selector": "form.bui-form"}, father, self.timeout)

    # Test_add
    def calendar(self):
        '''
        bui 日历控件

        :Return:
            返回PopWindow对象

        :Example:
         - 例1: menu = FrontEnd(driver).calendar()
        '''

        return Calendar(self.driver, self.timeout)

class Menu(BaseElement):
    '''bui的菜单操作'''

    def select_menu(self, menuInfo, frameidname=None, timeout=10):
        '''
        bui的菜单栏操作

        :Args:
         - menuInfo: 菜单栏点击文本，以'/'分隔点击顺序
         - frameidname: frame的id或name
         - timeout: frame跳转的超时时间

        :Raises:
            SeleniumError: 菜单操作失败
        '''
        try:
            re_block = r'display:\s*block;'
            # 保证菜单操作在最外层frame进行
            self.driver.switch_to.default_content()
            # menu_div = self.driver.find_element_by_attribute(
            #     'css selector', 'div.sys-menu-lists', timeout=self.timeout)
            menu_div = self.element
            upul = menu_div.find_element_by_attribute('css selector', 'ul.sys-menu-ul',
                                                      timeout=self.timeout)
            valuelist = menuInfo.split("/")
            for value in valuelist:
                if upul is not None:
                    upul = self.__click_node_by_nodename(upul, value)
                    sleep(1)
                else:
                    third_menu_div = self.driver.isdisplayed(
                        'css selector', 'div.three-child-menu', timeout=self.timeout)
                    if third_menu_div:
                        updiv = third_menu_div.find_element_by_attribute(
                            'css selector', 'div#child-menu-content>div.child-menu-warp',
                            timeout=self.timeout)
                        dl = updiv.find_element_by_attribute(
                            'css selector', 'dl.menu-down', 'style:' + re_block,
                            timeout=self.timeout)
                        link = dl.find_element_by_attribute(
                            'css selector', 'a.js-handler', 'text:' + value, timeout=self.timeout)
                        link.Click()
            BUI(self.driver).wait_page_loading(timeout)
            Frame(self.driver).switch_frame(frameidname, timeout)
        except Exception as msg:
            # logger.error(str(msg))
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def __click_node_by_nodename(self, upul: WebElement, value):
        re_open_lis = [r'showChild', 'open']
        ul = None
        lis = upul.find_elements_by_attribute('xpath', './li', timeout=self.timeout)
        for li in lis:
            link = li.find_element_by_attribute('xpath', './a', timeout=self.timeout)
            if link.text == value:
                logger.info('打开菜单：' + value)
                # 菜单栏未打开时点击栏目打开
                b_open = False
                for re_open_li in re_open_lis:
                    if re.search(re_open_li, li.get_attribute('class')):
                        b_open = True
                        break
                if not b_open:
                    link.secure_click()
                ul = li.exist('xpath', './ul', timeout=self.timeout)
                break
        return ul

class Frame():
    '''bui的frame操作'''

    def __init__(self, driver, timeout=10000):
        self.driver = driver
        self.timeout = timeout

    def swtich_to_defatul_content(self):
        '''
        bui 从frame贴换到主文档
        '''
        self.driver.switch_to.default_content()

    def switch_frame(self, frameidnames=None, timeout=10):
        '''
        切换bui的frame

        :Args:
         - frameidname: frame的ID或者Name；默认是没有ID和Name, 可以传入多个frameidname用/分隔
        '''
        re_none = r'display:\s*none;*'
        # 先切到主页
        self.driver.switch_to.default_content()
        # 再从主页切到frame页
        if frameidnames:
            frameidnames_split = frameidnames.strip().split("/")
            for frame in frameidnames_split:
                self.driver.switch_to.frame(frame)
        else:
            timeout1 = 0
            while timeout1 < timeout:
                frame_updiv = self.driver.exist('class name', 'ui-page-tab-iframe',
                                                timeout=self.timeout)
                if frame_updiv:
                    frames = frame_updiv.find_elements_by_attribute('xpath', './iframe',
                                                                    timeout=self.timeout)
                    i = 0
                    for frame in frames:
                        if re.search(re_none, frame.get_attribute('style')):
                            i += 1
                            continue
                        else:
                            name = frame.get_attribute('name')
                            if name:
                                logger.debug('切换到frame:' + name)
                                self.driver.switch_to.frame(name)
                                break
                            id = frame.get_attribute('id')
                            if id:
                                logger.debug('切换到frame:' + id)
                                self.driver.switch_to.frame(id)
                                break
                            self.driver.switch_to.frame(i)
                            break
                    if i == len(frames):
                        timeout1 += 1
                        sleep(1)
                    else:
                        break
                else:
                    break
            else:
                self.driver.switch_to.default_content()

class PopWindow():
    '''bui的div弹出框操作'''

    def __init__(self, driver, timeout):
        self.driver = driver
        self.timeout = timeout

    def pop_window(self, idname=None):
        '''
        定位bui的div弹出框

        :Args:
         - idname: 弹出框的定位条件
         - idname[0]: 元素查找方式
         - idname[1]: 元素查找语句
         - idname[2]: 查找的辅助属性

        :Returns:
            弹出框元素
        '''
        if not isinstance(idname, dict):
            raise AttributeError('element_para参数类型不正确！')

        key_list = [By.ID, By.NAME, By.CLASS_NAME, By.TAG_NAME, By.LINK_TEXT,
                    By.PARTIAL_LINK_TEXT, By.CSS_SELECTOR, By.XPATH]
        element_by = ''
        element_value = ''
        assist = ''
        for key, value in idname.items():
            if key in key_list:
                element_by = key
                element_value = value
            else:
                assist += '{}:{},'.format(key, value)
        assist = assist.strip(',')

        try:
            pop_class = r'bui-dialog'
            # 先切换到主页
            self.driver.switch_to.default_content()
            if idname:
                popdiv = self.driver.find_element_by_attribute(element_by, element_value, assist=assist,
                                                               timeout=self.timeout, switchframe=True)
            else:
                popdiv = self.driver.find_element_by_attribute(
                    'css selector', 'div.' + pop_class, timeout=self.timeout, switchframe=True)

            pop_header = popdiv.exist('xpath', './div[@class=\'bui-stdmod-header\']', timeout=self.timeout)
            if pop_header:
                logger.info('当前操作弹出框：' + pop_header.text)
            else:
                logger.info('打开弹出框。')
            return popdiv
        except Exception as msg:
            logger.warn(str(msg))
            print(traceback.format_exc())
            return None

class Button(BaseElement):
    '''bui的按钮操作'''

    def click(self):
        '''
        bui的按钮点击

        :Example:
         - 例: button.click()
        '''
        button_text = self.element.text
        if not button_text:
            button_text = self.element.get_attribute('title')
        logger.info('点击按钮：' + button_text)
        self.element.secure_click()

    def button_click_in_table_toolbar(self, text, idname=None, father=None):
        '''
        bui表格工具区的按钮点击功能

        :Args:
         - text: 按钮的名称，以'/'分隔点击顺序
         - idname: toolbar的定位条件
         - idname[0]: 元素查找方式
         - idname[1]: 元素查找语句
         - idname[2]: 查找的辅助属性
         - father: toolbar的祖先级元素，可以给控件查找限定范围，这样就不需要在整个页面中查找

        :Raises:
            SeleniumError: 按钮点击操作失败
        '''
        re_visible = r'visibility: visible;'
        try:
            if father is None:
                father = self.driver
            if idname and (len(idname) > 1 and len(idname) < 4):
                if len(idname) is 2:
                    toolbar_div = father.find_element_by_attribute(idname[0], idname[1], timeout=self.timeout)
                else:
                    toolbar_div = father.find_element_by_attribute(idname[0], idname[1], idname[2],
                                                                   timeout=self.timeout)
            else:
                toolbar_div = father.find_element_by_attribute(
                    'css selector', 'div.search-grid-container>div#grid-tbar', timeout=self.timeout)
            textlist = text.split('/')
            button = toolbar_div.exist(
                'css selector:button.button-small', 'text:' + textlist[0], timeout=1)
            if not button:
                em = toolbar_div.exist('css selector', 'em.show-hidden-tab', timeout=self.timeout)
                if em:
                    em.secure_click()
                    button = toolbar_div.find_element_by_attribute(
                        'css selector', 'button.button-small', 'text:' + textlist[0],
                        timeout=self.timeout)
                else:
                    logger.error('未找到 ' + textlist[0] + ' 按钮!')
                    raise SeleniumError('未找到 ' + textlist[0] + ' 按钮!')
            button.secure_click()
            logger.info('点击按钮：' + textlist[0])
            if len(textlist) > 1:
                btn_ul = self.driver.find_element_by_attribute(
                    'css selector', 'ul.bui-pop-menu', 'style:' + re_visible, timeout=self.timeout)
                select_li = btn_ul.find_element_by_attribute(
                    'css selector', 'li.bui-menu-item', 'text:' + textlist[1], timeout=self.timeout)
                select_li.secure_click()
                logger.info('点击按钮：' + textlist[1])
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def span_click_in_table(self, text, father=None):
        '''
        bui表格中的小图标点击方法

        :Args:
         - text: span的title属性值
         - father: span按钮的祖先级元素，可以给控件查找限定范围，这样就不需要在整个页面中查找
        '''
        try:
            if not father:
                father = self.driver
            span_group = father.find_element_by_attribute(
                'css selector', 'div.bui-grid-cell-inner>span.bui-grid-cell-text',
                timeout=self.timeout)
            span = span_group.find_element_by_attribute(
                'css selector', 'span.btn-img', 'title:' + text, timeout=self.timeout)
            span.secure_click()
            logger.info('点击图标：' + text)
        except Exception as msg:
            logger.warn(str(msg))
            print(traceback.format_exc())

class Table():
    '''bui的表格操作'''

    def __init__(self, driver, timeout=10000):
        self.driver = driver
        self.timeout = timeout

    def set_options(self, conditions):
        '''
        设置bui的表格查询项或者表格显示列

        :Args:
         - conditions: 条件列表，以'/'分隔
        '''
        try:
            # 先切换到主页
            self.driver.switch_to.default_content()
            # 查找配置窗口
            updiv = self.driver.find_element_by_attribute(
                'css selector', 'div.ms2side__div', timeout=self.timeout, switchframe=True)
            # 先将所有配置清空
            option_div = updiv.find_element_by_attribute('css selector', 'div.ms2side__options',
                                                         timeout=self.timeout)
            option_div.find_element_by_attribute('css selector', 'p.RemoveAll',
                                                 timeout=self.timeout).secure_click()
            # 添加条件
            condition_list = conditions.split('/')
            if len(condition_list) == 1 and condition_list[0].lower() == 'all':
                addall_p = option_div.find_element_by_attribute('css selector', 'p.AddAll',
                                                                timeout=self.timeout)
                addall_p.secure_click()
            elif len(condition_list) > 0:
                selectdiv = updiv.find_element_by_attribute(
                    'css selector', 'div.ms2side__select>div.ms2side__header', 'text:可选',
                    timeout=self.timeout)
                options = selectdiv.find_elements_by_attribute(
                    'xpath', './following-sibling::select/option', timeout=self.timeout)
                # # 消除默认选中
                # options[0].secure_click()
                add_p = option_div.find_element_by_attribute('css selector', 'p.AddOne',
                                                             timeout=self.timeout)
                for condition in condition_list:
                    for option in options:
                        option_text = option.text.strip()
                        if condition == option_text:
                            option.secure_click()
                            add_p.secure_click()
                            break
            else:
                pass
            # 先切换到主页
            self.driver.switch_to.default_content()
            save_button = self.driver.find_element_by_attribute(
                'tag name', 'button', 'text:保存', timeout=self.timeout, switchframe=True)
            save_button.secure_click()
        except Exception as msg:
            logger.warn(str(msg))
            print(traceback.format_exc())

    def get_table_cell(self, tableInfo, titlename, idname=None, father=None):
        '''
        获取bui表格单元格

        :Args:
         - tableInfo: 待查找单元格所在行的某单元格值和该单元格所在列的列名信息，字典类型，格式：{列名:值}
         - titlename: 待查找单元格所在列的列名，字符串类型
         - idname: 表格的定位条件
         - idname[0]: 元素查找方式
         - idname[1]: 元素查找语句
         - idname[2]: 查找的辅助属性
         - father: table的祖先级元素，可以给表格查找限定范围，这样就不需要在整个页面中查找

        :Returns:
            返回表格单元格元素

        :Raises:
            SeleniumError: 获取表格单元格失败
        '''
        if idname and not isinstance(idname, dict):
            raise AttributeError('element_para参数类型不正确！')
        elif idname:
            key_list = [By.ID, By.NAME, By.CLASS_NAME, By.TAG_NAME, By.LINK_TEXT,
                        By.PARTIAL_LINK_TEXT, By.CSS_SELECTOR, By.XPATH]
            element_by = ''
            element_value = ''
            assist = ''
            for key, value in idname.items():
                if key in key_list:
                    element_by = key
                    element_value = value
                else:
                    assist += '{}:{},'.format(key, value)
            assist = assist.strip(',')

        try:
            logger.info('开始表格行号查询')
            if father is None:
                father = self.driver

            if idname:
                 table_div = father.find_element_by_attribute(element_by, element_value, assist,
                                                                 timeout=self.timeout)
            else:
                table_div = father.find_element_by_attribute(
                    'css selector', 'div.search-grid-container div#grid>div.bui-grid',
                    timeout=self.timeout)
            # 将表格翻到首页
            page_ul = table_div.find_element_by_attribute(
                'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
                'class:bui-pagingbar', timeout=self.timeout)
            page_first = page_ul.find_element_by_attribute('xpath', './li[@id="first"]/button',
                                                           timeout=self.timeout)
            if page_first.is_enabled():
                page_first.secure_click()
            # 获取列名列表
            head_table = table_div.find_element_by_attribute('css selector',
                                                             'div.bui-grid-header-container>div.bui-grid-header>table.bui-grid-table',
                                                             timeout=self.timeout)
            titlelist = self.get_bui_table_title(head_table)
            logger.debug('表格显示列名：' + str(titlelist))
            row = self.__get_table_page_row(table_div, titlelist, tableInfo)
            logger.debug('表格行号查询结束！')
            logger.debug('开始表格单元格查询')
            # 计算单元格在当前页的行号
            rows_ul = table_div.find_element_by_attribute(
                'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
                'class:pull-left', timeout=self.timeout)
            rows_select = rows_ul.find_element_by_attribute('xpath', './li/div/select',
                                                            timeout=self.timeout)
            rows_oplist = rows_select.find_elements_by_attribute('tag name', 'option',
                                                                 timeout=self.timeout)
            rows = 0
            for op in rows_oplist:
                if op.is_selected():
                    # rows = int(op.gettext())
                    rows = int(op.text)
                    break
            if row % rows == 0:
                row = rows
            else:
                row = row % rows
            # 根据列名和行数查找单元格
            table_cell = self.__get_table_page_cell(table_div, titlelist, titlename, row)
            logger.debug('单元格查询结束！')
            return table_cell
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def get_table_data_by_titlename(self, titlename, idname=None, father=None):
        '''
        获取bui表格某列的所有数据

        :Args:
         - titlename: 待查找单元格所在列的列名，字符串类型
         - idname: 表格的定位条件
         - idname[0]: 元素查找方式
         - idname[1]: 元素查找语句
         - idname[2]: 查找的辅助属性
         - father: table的祖先级元素，可以给表格查找限定范围，这样就不需要在整个页面中查找

        :Returns:
            返回表格列数据

        :Raises:
            SeleniumError: 获取表格列数据失败
        '''
        if idname and not isinstance(idname, dict):
            raise AttributeError('element_para参数类型不正确！')
        elif idname:
            key_list = [By.ID, By.NAME, By.CLASS_NAME, By.TAG_NAME, By.LINK_TEXT,
                        By.PARTIAL_LINK_TEXT, By.CSS_SELECTOR, By.XPATH]
            element_by = ''
            element_value = ''
            assist = ''
            for key, value in idname.items():
                if key in key_list:
                    element_by = key
                    element_value = value
                else:
                    assist += '{}:{},'.format(key, value)
            assist = assist.strip(',')

        try:
            if father is None:
                father = self.driver

            if idname:
                table_div = father.find_element_by_attribute(element_by, element_value, assist,
                                                                 timeout=self.timeout)
            else:
                table_div = father.find_element_by_attribute(
                    'css selector', 'div.search-grid-container div#grid>div.bui-grid',
                    timeout=self.timeout)
            # 将表格翻到首页
            page_ul = table_div.find_element_by_attribute(
                'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
                'class:bui-pagingbar', timeout=self.timeout)
            page_first = page_ul.find_element_by_attribute('xpath', './li[@id="first"]/button',
                                                           timeout=self.timeout)
            if page_first.is_enabled():
                page_first.secure_click()
            # 获取列名列表
            head_table = table_div.find_element_by_attribute('css selector',
                                                             'div.bui-grid-header-container>div.bui-grid-header>table.bui-grid-table',
                                                             timeout=self.timeout)
            titlelist = self.get_bui_table_title(head_table)
            logger.debug('表格显示列名：' + str(titlelist))
            # 根据列名和行数查找单元格
            table_data = self.__get_table_page_texts(table_div, titlelist, titlename)
            return table_data
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def __get_table_page_row(self, table_div: WebElement, titlelist, tableInfo):
        keylist = list(tableInfo.keys())
        logger.debug('表格查找列名索引：' + str(keylist))
        body_table = table_div.find_element_by_attribute(
            'css selector', 'div.bui-grid-body>table.bui-grid-table', timeout=self.timeout)
        # 以输入数据作为索引查找表格行数
        rowlist_list = list()
        rows = 0
        for key in keylist:
            templist = list()
            titleindex = titlelist.index(key)
            logger.debug('第' + str(titleindex + 1) + '列，名称：' + key)
            textlist = self.get_bui_table_text(body_table, len(titlelist), int(titleindex + 1))
            rows = len(textlist)
            logger.debug('当前页显示行数：' + str(rows))
            for j in range(0, rows):
                if textlist[j] == tableInfo[key]:
                    logger.debug('要查找的内容：' + tableInfo[key])
                    logger.debug('第' + str(j + 1) + '行，内容：' + textlist[j])
                    row = j + 1
                    templist.append(row)
            rowlist_list.append(templist)
        rowlist = rowlist_list[0]
        for i in range(1, len(rowlist_list)):
            rowlist = get_same_value_in_lists(rowlist, rowlist_list[i])
        # 未找到数据行则进行表格翻页
        if len(rowlist) > 0:
            return rowlist[0]
        else:
            page_ul = table_div.find_element_by_attribute(
                'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
                'class:bui-pagingbar', timeout=self.timeout)
            page_next = page_ul.find_element_by_attribute('xpath', './li[@id="next"]/button',
                                                          timeout=self.timeout)
            if page_next.is_enabled():
                page_next.secure_click()
                return self.__get_table_page_row(table_div, titlelist, tableInfo) + rows
            else:
                raise SeleniumError("未找到目标数据行！")

    def __get_table_page_cell(self, table_div: WebElement, titlelist, titlename, row):
        # 获取表格单元格列表
        body_table = table_div.find_element_by_attribute(
            'css selector', 'div.bui-grid-body>table.bui-grid-table', timeout=self.timeout)
        celllist = self.get_bui_table_cell(body_table)
        # 计算当前显示的表格行数
        rows = len(celllist) / len(titlelist)
        logger.debug('当前页显示行数：{}/{}={}'.format(len(celllist), len(titlelist), rows))
        # 行数若超过当前页面显示行数，则翻页
        if row <= 0:
            raise SeleniumError('表格行号出错！')
        elif row > rows:
            page_ul = table_div.find_element_by_attribute(
                'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
                'class:bui-pagingbar', timeout=self.timeout)
            page_next = page_ul.find_element_by_attribute('xpath', './li[@id="next"]/button',
                                                          timeout=self.timeout)
            if page_next.is_enabled():
                page_next.secure_click()
                table_cell = self.__get_table_page_cell(table_div, titlelist, titlename, row)
            else:
                raise SeleniumError('行数已超出表格总行数！')
        else:
            titleindex = titlelist.index(titlename)
            logger.debug('第' + str(titleindex) + '列，名称：' + titlename)
            cellindex = int(titleindex + (len(titlelist) * (row - 1)))
            table_cell = celllist[cellindex]
        return table_cell

    def __get_table_page_texts(self, table_div: WebElement, titlelist, titlename):
        # 获取表格单元格列表
        body_table = table_div.find_element_by_attribute(
            'css selector', 'div.bui-grid-body>table.bui-grid-table', timeout=self.timeout)
        titleindex = titlelist.index(titlename)
        logger.debug('要获取第' + str(titleindex + 1) + '列的内容。')
        textlist = self.get_bui_table_text(body_table, len(titlelist), int(titleindex + 1))
        logger.debug('当前页第' + str(titleindex + 1) + '列的内容：' + str(textlist))
        # 翻页
        page_ul = table_div.find_element_by_attribute(
            'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
            'class:bui-pagingbar', timeout=self.timeout)
        page_next = page_ul.find_element_by_attribute('xpath', './li[@id="next"]/button',
                                                      timeout=self.timeout)
        if page_next.is_enabled():
            page_next.secure_click()
            textlist.extend(self.__get_table_page_texts(table_div, titlelist, titlename))
            return textlist
        else:
            return textlist

    def export_table_data_to_excel(self, file, defaultpath=False, idname=None, father=None):
        '''
        导出bui表格所有数据到excel

        :Args:
         - file: 导出的文件名，包含路径
         - defaultpath: 默认地址标记
         - idname: 表格的定位条件
         - idname[0]: 元素查找方式
         - idname[1]: 元素查找语句
         - idname[2]: 查找的辅助属性
         - father: table的祖先级元素，可以给表格查找限定范围，这样就不需要在整个页面中查找

        :Raises:
            SeleniumError: 获取表格数据出错或者导出表格出错
        '''
        try:
            if father is None:
                father = self.driver
            if idname and (len(idname) > 1 and len(idname) < 4):
                if len(idname) is 2:
                    table_div = father.find_element_by_attribute(idname[0], idname[1], timeout=self.timeout)
                else:
                    table_div = father.find_element_by_attribute(idname[0], idname[1], idname[2],
                                                                 timeout=self.timeout)
            else:
                table_div = father.find_element_by_attribute(
                    'css selector:div.search-grid-container>div#grid>div.bui-grid',
                    timeout=self.timeout)
            # 将表格翻到首页
            page_ul = table_div.find_element_by_attribute(
                'xpath', './parent::div/following-sibling::div[@id="grid-bbar"]/ul/ul',
                'class:bui-pagingbar', timeout=self.timeout)
            page_first = page_ul.find_element_by_attribute(
                'xpath', './li[@id="first"]/button', timeout=self.timeout)
            if page_first.is_enabled():
                page_first.secure_click()
            # 获取列名列表
            head_table = table_div.find_element_by_attribute('css selector',
                                                             'div.bui-grid-header-container>div.bui-grid-header>table.bui-grid-table',
                                                             timeout=self.timeout)
            titlelist = self.get_bui_table_title(head_table)
            logger.debug('表格显示列名：' + str(titlelist))
            # 逐页获取当前页表格的所有数据
            textlist = list()
            body_table = table_div.find_element_by_attribute(
                'css selector', 'div.bui-grid-body>table.bui-grid-table', timeout=self.timeout)
            while True:
                times = 0
                while times < 5:
                    try:
                        templist = self.get_bui_table_text(body_table)
                        textlist.extend(templist)
                        break
                    except SeleniumExceptions.StaleElementReferenceException as msg:
                        logger.debug(str(msg))
                        times += 1
                        sleep(0.2)
                page_next = page_ul.find_element_by_attribute('xpath', './li[@id="next"]/button',
                                                              timeout=self.timeout)
                if page_next.is_enabled():
                    page_next.secure_click()
                else:
                    break
            # 导出到文件
            rows = int(len(textlist) / len(titlelist))
            cols = len(titlelist)
            titlelist.extend(textlist)
            # 拼装文件地址
            if defaultpath and isinstance(defaultpath, bool):
                defaultpath = Variable().get_variable('varu_ResultDriver')
                file = os.path.join(defaultpath, file)
            elif defaultpath and isinstance(defaultpath, str):
                file = os.path.join(defaultpath, file)
            # 导出到excel
            from hslib.excel import ExcelWrite
            excel = ExcelWrite()
            excel.write_by_table_data(titlelist, rows + 1, cols)
            excel.save(file)
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def get_bui_table_title(self, table: WebElement):
        """
        获取bui的table的列名，hidden列除外，以列表的形式返回

        :Args:
         - table: 表格的列名所在table元素

        :Returns:
            返回表格列名集合

        :Raises:
            SeleniumError: 参数为非table元素
        """
        hidden_class = r'bui-grid-hd-empty'
        if table.tag_name == 'table':
            titlelist = list()
            thead = table.find_element_by_attribute(r'tag name', 'thead', timeout=self.timeout)
            thlist = thead.find_elements_by_attribute('tag name', 'th', timeout=self.timeout)
            for th in thlist:
                if hidden_class not in th.get_attribute('class'):
                    th.focus()
                    text = th.text.strip()
                    titlelist.append(text)
            return titlelist
        else:
            logger.error('元素对象不为table对象，对象类型为：' + table.tag_name)
            raise SeleniumError('元素对象不为table对象，对象类型为：' + table.tag_name)

    def get_bui_table_text(self, table: WebElement, columns=0, column=0, timeout=5):
        '''
        获取bui表格列文本集合

        :Args:
         - table: table元素
         - columns: 表格总列数
         - column: 所需获取列的列号

        :Returns:
            返回当前页的列文本集合

        :Raises:
            SeleniumError: 参数为非table元素
        '''
        if table.tag_name == 'table':
            bodylist = list()
            times = 0
            while times < (timeout * 5):
                try:
                    tdlist = self.get_bui_table_cell(table)
                    for i in range(0, len(tdlist)):
                        if columns:
                            if (i + 1) % columns == column % columns:
                                tdlist[i].focus()
                                text = tdlist[i].text.strip()
                                bodylist.append(text)
                        else:
                            tdlist[i].focus()
                            text = tdlist[i].text.strip()
                            bodylist.append(text)
                    break
                except SeleniumExceptions.StaleElementReferenceException as msg:
                    logger.debug(str(msg))
                    times += 1
                    sleep(0.2)
            return bodylist
        else:
            logger.error('元素对象不为table对象，对象类型为：' + table.tag_name)
            raise SeleniumError('元素对象不为table对象，对象类型为：' + table.tag_name)

    def get_bui_table_cell(self, table: WebElement, timeout=5):
        """
        获取bui表格列单元格集合

        :Args:
         - table: table元素
         - columns: 表格总列数
         - column: 所需获取列的列号

        :Returns:
            返回当前页的列单元格集合

        :Raises:
            SeleniumError: 参数为非table元素
        """
        hidden_class = r'bui-grid-cell-empty'
        if table.tag_name == 'table':
            celllist = list()
            times = 0
            while times < (timeout * 5):
                try:
                    celllist.clear()
                    tbody = table.find_element_by_attribute('tag name', 'tbody', timeout=self.timeout)
                    tdlist = tbody.find_elements_by_attribute('css selector', 'td.bui-grid-cell',
                                                              timeout=self.timeout)
                    for td in tdlist:
                        if hidden_class not in td.get_attribute('class'):
                            celllist.append(td)
                    break
                except SeleniumExceptions.StaleElementReferenceException as msg:
                    logger.debug(str(msg))
                    times += 1
                    sleep(0.2)
            return celllist
        else:
            logger.error('元素对象不为table对象，对象类型为：' + table.tag_name)
            raise SeleniumError('元素对象不为table对象，对象类型为：' + table.tag_name)

class Form(BaseElement):
    '''bui的表单操作'''

    def do_form(self, inputdata, father=None, idname=None):
        '''
        bui的表单一键抓取功能

        :Args:
         - inputdata: 输入数据，需要定位的表单抬头和待输入文本
         - idname: 表单的定位条件
         - idname[0]: 元素查找方式
         - idname[1]: 元素查找语句
         - idname[2]: 查找的辅助属性
         - father: 表单的祖先级元素，可以给表格查找限定范围，这样就不需要在整个页面中查找

        :Returns:
            操作失败返回false，成功返回true

        :Raises:
            SeleniumError: 表单填充出错
        '''
        try:
            if father is None:
                father = self.driver

            form = self.element
            for input_key, input_value in inputdata.items():
                if input_value == '':
                    continue
                key, value, flag, label_seq = deal_inputdata(input_key, input_value)
                label = form.find_elements_by_attribute(
                    'css selector', 'label.control-label', 'text:' + key,
                    timeout=self.timeout)[label_seq - 1]
                divspan = label.find_element_by_attribute(
                    'xpath', './following-sibling::*', 'class:controls', timeout=self.timeout)
                temp_pass = self.confirm_type(divspan, key, value, flag)
                if temp_pass is False:
                    return False
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))
        else:
            return True

    def confirm_type(self, divspan: WebElement, key, value, flag):
        '''
        判断bui控件类型

        :Args:
         - divspan: label后的span
         - key: label文本
         - value: 控件赋值
         - flag: 控件操作标记

        :Returns:
            填充失败返回False
        '''
        re_calendar_time = r'calendar-time'
        re_calendar = r'calendar'
        re_select = r'bui-select-input'
        re_dropdown = r'hs-search-input'
        re_search = r'selector-show'
        inputs = self.get_all_form_control(divspan)
        input_type = inputs[0].get_attribute('type')
        if input_type == 'radio':
            logger.debug(key + '：单选按钮')
            if self.deal_radio(inputs, key, value, flag) is False:
                return False
            return True
        elif input_type == 'checkbox':
            logger.debug(key + '：复选框')
            if self.deal_checkbox(inputs, key, value, flag) is False:
                return False
            return True
        else:
            if len(inputs) == 1:
                tag_name = inputs[0].tag_name
                if tag_name == 'textarea':
                    logger.debug(key + '：多行文本框')
                    if self.deal_text(inputs[0], key, value, flag) is False:
                        return False
                    return True
                elif tag_name == 'select':
                    logger.debug(key + '：单选下拉框')
                    if self.deal_select(inputs[0], key, value, flag) is False:
                        return False
                    return True
                elif input_type == 'text' or input_type == 'password':
                    logger.debug(key + '：文本框/密码框格式')
                    input_class = inputs[0].get_attribute('class')
                    if re.search(re_calendar_time, input_class):
                        logger.debug(key + '：日期时间控件')
                        if self.deal_calendar_time(inputs[0], key, value, flag) is False:
                            return False
                        return True
                    elif re.search(re_calendar, input_class):
                        logger.debug(key + '：日期控件')
                        if self.deal_calendar(inputs[0], key, value, flag) is False:
                            return False
                        return True
                    elif re.search(re_select, input_class):
                        logger.debug(key + '：多选下拉框控件')
                        if self.deal_select_multiple(inputs[0], key, value, flag) is False:
                            return False
                        return True
                    elif re.search(re_search, input_class):
                        logger.debug(key + '：搜索框控件')
                        if self.deal_select_dropdown(inputs[0], key, value, flag) is False:
                            return False
                        return True
                    elif re.search(re_dropdown, input_class):
                        if inputs[0].is_readonly():
                            img = inputs[0].exist('xpath', './following::img', timeout=self.timeout)
                            if not img:
                                logger.debug(key + '：下拉控件')
                                if self.deal_select_dropdown(inputs[0], key, value, flag) is False:
                                    return False
                                return True
                            else:
                                logger.warn(key + '：页面弹出控件暂时无法处理！')
                                return False
                        else:
                            logger.debug(key + '：文本框/密码框')
                            if self.deal_text(inputs[0], key, value, flag) is False:
                                return False
                            return True
                    else:
                        logger.debug(key + '：文本框/密码框')
                        if self.deal_text(inputs[0], key, value, flag) is False:
                            return False
                        return True
                else:
                    logger.warn(key + '：不是表单控件')
                    return False
            elif len(inputs) == 2:
                if len(value) != 2:
                    raise SeleniumError(key + '组合控件的数据格式不正确！')

                input_class = inputs[0].get_attribute('class')
                if re.search(re_calendar_time, input_class):
                    logger.debug(key + '：日期时间控件组')
                    if self.deal_calendar_time_group(inputs, key, value, flag) is False:
                        return False
                    return True
                elif re.search(re_calendar, input_class):
                    logger.debug(key + '：日期控件组')
                    if self.deal_calendar_group(inputs, key, value, flag) is False:
                        return False
                    return True
                else:
                    logger.debug(key + '：文本框/密码框组')
                    if self.deal_text_group(inputs, key, value, flag) is False:
                        return False
                    return True
            else:
                logger.warn(key + '：没有表单控件')
                return False

    def get_all_form_control(self, updiv: WebElement):
        '''
        获取bui的所有Form控件

        :Args:
         - updiv: 控件所在祖先节点，label的父节点

        :Returns:
            返回控件列表
        '''
        # 先查找input元素
        try:
            re_none = r'display:\s*none;'
            inputs = updiv.find_elements_by_attribute('tag name', 'input', timeout=1)
            typelist = ['text', 'password', 'radio', 'checkbox']
            i = 0
            while i < len(inputs):
                input_type = inputs[i].get_attribute('type')
                input_style = inputs[i].get_attribute('style')
                if input_type not in typelist or re.search(re_none, input_style):
                    inputs.remove(inputs[i])
                else:
                    i += 1
            if len(inputs) == 0:
                raise SeleniumError('当前input控件不可用！')
            return inputs
        except SeleniumError:
            # 未找到input则再查找select元素
            try:
                selects = updiv.find_elements_by_attribute('tag name', 'select', timeout=1)
                return selects
            except SeleniumError:
                # input和select都未找到则查找textarea
                try:
                    textareas = updiv.find_elements_by_attribute('tag name', 'textarea', timeout=1)
                    return textareas
                except SeleniumError:
                    logger.warn('未找到form控件！')
                    return list()

    def deal_text(self, inputele: WebElement, key, value, flag='assign'):
        '''
        处理bui文本框

        :Args:
         - inputele: 文本框控件
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            textType = TextType(inputele)
            if flag == 'assign':
                logger.info(key + '进行文本框填充。')
                inputele.clear()
                textType.set_value(value[0])
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return textType.is_default(value[0])
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_text_group(self, inputs, key, value, flag='assign'):
        '''
        处理bui文本框组

        :Args:
         - inputs: 文本框控件组
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            textType = TextType(self.driver)
            if flag == 'assign':
                logger.info(key + '进行文本框组填充。')
                for i in range(0, len(inputs)):
                    inputs[i].clear()
                    inputs[i].send_keys(value[i])
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return textType.is_default_for_group(inputs, value)
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_select(self, inputele: WebElement, key, value, flag='assign'):
        '''
        bui的普通单选下拉框处理

        :Args:
         - inputele: 下拉框控件
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            select = Select(element_para=inputele)
            if flag == 'assign':
                logger.info(key + '进行下拉框选择。')
                select.select(value[0])
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return select.is_default_for_single(value[0])
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_select_multiple(self, inputele: WebElement, key, value, flag='assign'):
        '''
        bui的复选下拉框控件操作

        :Args:
         - inputele: 下拉框控件
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            re_visible = r'visibility: visible;'
            select = Select(self.driver)
            if flag == 'assign' or flag == 'all':
                logger.info(key + '进行多选下拉框选择。')
                inputele.secure_click()
                updiv = self.driver.find_element_by_attribute(
                    'css selector', 'div.bui-list-picker', 'style:' + re_visible,
                    timeout=self.timeout)
                div = updiv.find_element_by_attribute('css selector', 'div.bui-select-list',
                                                      timeout=self.timeout)
                if flag == 'all':
                    select.set_value_for_multiple(div)
                elif flag == 'assign':
                    select.set_value_for_multiple(div, value)
                return
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def A   (self, inputele: WebElement, key, value, flag='assign'):
        '''
        bui的单选下拉树框控件操作

        :Args:
         - inputele: 下拉树框控件
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            re_tree = r'bui-tree-picker'
            re_visible = r'visibility: visible;'
            select = Select(self.driver)
            if flag == 'assign':
                inputele.secure_click()
                updiv = self.driver.find_element_by_attribute(
                    'css selector', 'div.bui-list-picker', 'style:' + re_visible,
                    timeout=self.timeout)
                updiv_class = updiv.get_attribute('class')
                if re_tree in updiv_class:
                    logger.info(key + '进行单选下拉树框选择。')
                    div = updiv.find_element_by_attribute('css selector', 'div.bui-tree-list',
                                                          timeout=self.timeout)
                    select.set_value_for_tree_single(div, value[0])
                    return
                else:
                    logger.info(key + '进行下拉搜索框选择。')
                    div = updiv.find_element_by_attribute('css selector', 'div.bui-simple-list',
                                                          timeout=self.timeout)
                    select.set_value_for_search(div, value[0])
                    return
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_calendar(self, inputele: WebElement, key, value, flag='assign'):
        '''
        bui的日期选择控件操作

        :Args:
         - inputele: 日期控件
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            re_visible = r'visibility:\s*visible;'
            calendar = Calendar(self.driver)
            text = value[0]
            if flag == 'assign':
                logger.info(key + '进行日期控件选择。')
                inputele.secure_click()
                updiv = self.driver.find_element_by_attribute(
                    'css selector', 'div.bui-datepicker', 'style:' + re_visible,
                    timeout=self.timeout)
                div = updiv.find_element_by_attribute('css selector', 'div.bui-calendar',
                                                      timeout=self.timeout)
                calendar.set_value(div, text)
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return calendar.is_default(inputele, value[0])
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_calendar_group(self, inputs, key, value, flag='assign'):
        '''
        bui的日期选择控件组操作

        :Args:
         - inputs: 日期控件组
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            re_visible = r'visibility:\s*visible;'
            calendar = Calendar(self.driver)
            if flag == 'assign':
                logger.info(key + '进行日期控件组选择。')
                for i in range(0, len(inputs)):
                    inputs[i].secure_click()
                    updiv = self.driver.find_element_by_attribute(
                        'css selector', 'div.bui-datepicker', 'style:' + re_visible,
                        timeout=self.timeout)
                    div = updiv.find_element_by_attribute('css selector', 'div.bui-calendar',
                                                          timeout=self.timeout)
                    calendar.set_value(div, value[i])
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return calendar.is_default_for_group(inputs, value)
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_calendar_time(self, inputele: WebElement, key, value, flag='assign'):
        '''
        bui的日期时间控件操作

        :Args:
         - inputele: 日期时间控件
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            re_visible = r'visibility:\s*visible;'
            calendar = Calendar(self.driver)
            text = value[0]
            if flag == 'assign':
                logger.info(key + '进行日期时间控件选择。')
                inputele.secure_click()
                updiv = self.driver.find_element_by_attribute(
                    'css selector', 'div.bui-datepicker', 'style:' + re_visible,
                    timeout=self.timeout)
                div = updiv.find_element_by_attribute('css selector', 'div.bui-calendar',
                                                      timeout=self.timeout)
                calendar.set_value_for_time(div, text)
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return calendar.is_default(inputele, value[0])
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_calendar_time_group(self, inputs, key, value, flag='assign'):
        '''
        bui的日期时间控件组操作

        :Args:
         - inputs: 日期时间控件组
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            re_visible = r'visibility:\s*visible;'
            calendar = Calendar(self.driver)
            if flag == 'assign':
                logger.info(key + '进行日期时间控件组选择。')
                for i in range(0, len(inputs)):
                    inputs[i].secure_click()
                    updiv = self.driver.find_element_by_attribute(
                        'css selector', 'div.bui-datepicker', 'style:' + re_visible,
                        timeout=self.timeout)
                    div = updiv.find_element_by_attribute('css selector', 'div.bui-calendar',
                                                          timeout=self.timeout)
                    calendar.set_value_for_time(div, value[i])
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return calendar.is_default_for_group(inputs, value)
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_radio(self, inputs, key, value, flag='assign'):
        '''
        bui的单选按钮操作

        :Args:
         - inputs: 单选按钮控件组
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            radio = Radio(self.driver)
            if flag == 'assign':
                logger.info(key + '进行单选按钮选择。')
                radio.set_value(inputs, value[0])
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return radio.is_default(inputs, value[0])
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

    def deal_checkbox(self, inputs, key, value, flag='assign'):
        '''
        bui的复选框操作

        :Args:
         - inputs: 复选框控件组
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        try:
            checkbox = Checkbox(self.driver)
            if flag == 'assign':
                logger.info(key + '进行单选按钮选择。')
                checkbox.set_value(inputs, value)
                return
            elif flag == 'default':
                logger.info(key + '进行默认值检查。')
                return checkbox.is_default(inputs, value)
            else:
                logger.warn(key + '未进行任何操作。')
                return
        except Exception as msg:
            logger.error(str(msg))
            print(traceback.format_exc())
            raise SeleniumError(str(msg))

class Select(BaseElement):
    '''bui的下拉控件操作'''

    def __init__(self, element_para, father=None, timeout=5):
        if element_para:
            super().__init__(element_para, father, timeout)
        else:
            self.driver = father
            self.timeout = timeout

    def select(self, value=None):
        """
        对下拉框对象进行选取操作

        :Args:
         - value:要选取的下拉框值

        :Returns:
            value为None时获取所有select的选项

        :Raises:
            SeleniumError: 未找到选项或者当前元素不是select
        """
        if self.element.tag_name == 'select':
            # 需要判断第一个是否为无标题全选框
            titleelements = self.element.find_elements_by_attribute('tag name', 'option')
            if not value:
                return [item.text.strip() for item in titleelements]
            for each in titleelements:
                if each.text.strip() == value:
                    each.focus()
                    each.secure_click()
                    return
            logger.getlogger().debug('在下拉框中下没有找到' + value + '选项')
            raise SeleniumError('在下拉框中下没有找到' + value + '选项')
        else:
            logger.getlogger().debug('元素对象不为下拉框对象，对象类型为：' + self.element.tag_name)
            raise SeleniumError('元素对象不为下拉框对象，对象类型为：' + self.element.tag_name)

    def set_value_for_multiple(self, div: WebElement, value=['all']):
        '''
        bui的多选下拉框赋值

        :Args:
         - div: 下拉框div元素
         - value: 选项值列表
        '''
        re_selected = r'bui-list-item-selected'
        ul = div.find_element_by_attribute('xpath', './ul', timeout=self.timeout)
        lis = ul.find_elements_by_attribute('xpath', './li,class:bui-list-item',
                                            timeout=self.timeout)
        # 先全部清空
        for li in lis:
            if re_selected in li.get_attribute('class'):
                li.find_element_by_attribute('xpath', './span').secure_click()
        # 进行选择
        if len(value) == 1 and value[0] == 'all':
            for li in lis:
                if re_selected not in li.get_attribute('class'):
                    li.find_element_by_attribute('xpath', './span').secure_click()
        else:
            for va in value:
                for li in lis:
                    if va == li.text.strip():
                        if re_selected not in li.get_attribute('class'):
                            li.find_element_by_attribute('xpath', './span').secure_click()
                        break

    def set_value_for_tree_single(self, div: WebElement, value):
        '''
        bui的单选下拉树框赋值

        :Args:
         - div: 下拉树框div元素
         - value: 选项值
        '''
        valuelist = value.split('/')
        va_last = valuelist[-1]
        del valuelist[-1]
        if len(valuelist) > 0:
            for va in valuelist:
                li = div.find_element_by_attribute(
                    'css selector', 'li.bui-tree-item', 'text:' + va, timeout=self.timeout)
                if 'bui-tree-item-expanded' not in li.get_attribute('class'):
                    li.find_element_by_attribute('css selector', 'span.x-tree-elbow-expander',
                                                 timeout=self.timeout).secure_click()
        li_last = div.find_element_by_attribute(
            'css selector', 'li.bui-tree-item', 'text:' + va_last, timeout=self.timeout)
        li_last.secure_click()

    def set_value_for_search(self, div: WebElement, value):
        '''
        bui的下拉搜索框赋值

        :Args:
         - div: 下拉搜索框div元素
         - value: 搜索值
        '''
        # 输入进行搜索
        tbar_div = div.find_element_by_attribute('css selector', 'div.bui-grid-tbar',
                                                 timeout=self.timeout)
        inputele = tbar_div.find_element_by_attribute('css selector', 'input[type="text"]',
                                                      timeout=self.timeout)
        inputele.clear()
        inputele.send_keys(value)
        search_btn = tbar_div.find_element_by_attribute(
            'css selector', 'button', 'text:搜索', timeout=self.timeout)
        search_btn.secure_click()
        # 表格中数据行选取
        body_table = div.find_element_by_attribute(
            'css selector', 'div.bui-grid-body>table.bui-grid-table', timeout=self.timeout)
        trs = body_table.find_elements_by_attribute(
            'css selector', 'tr.bui-grid-row', timeout=self.timeout)
        span = trs[0].find_element_by_attribute(
            'css selector', 'td:nth-of-type(1)>div.bui-grid-cell-inner>span.bui-grid-cell-text',
            timeout=self.timeout)
        span.secure_click()
        # 关闭下拉框
        close_btn = tbar_div.exist('css selector', 'button', 'text:关闭', timeout=self.timeout)
        if close_btn:
            close_btn.secure_click()

    # def is_default_for_single(self, inputele: WebElement, value):
    def is_default_for_single(self, value):
        '''
        bui的单选下拉框默认值校验

        :Args:
         - inputele: 下拉框控件
         - value: 校验值
        '''
        options = self.element.find_elements_by_attribute('tag name', 'option', timeout=self.timeout)
        for option in options:
            if option.is_selected():
                text = option.text
                break
        else:
            text = options[0].text
        if text.strip() == value.strip():
            return True
        else:
            raise SeleniumError("默认值比匹配：期待的默认值为：{}; 实际的默认值为：{}".format(value, text))

class Calendar():
    '''bui的日历控件操作'''
    
    def __init__(self, driver, timeout = 5):
        self.driver = driver
        self.timeout = timeout

    def set_value(self, div: WebElement, text):
        control_ul = div.find_element_by_attribute('css selector', 'ul.bui-calendar-footer',
                                                   timeout=self.timeout)
        if text == '今天' or text.lower() == 'today':
            today_button = control_ul.find_element_by_attribute(
                'tag name', 'button', 'text:今天', timeout=self.timeout)
            today_button.secure_click()
        else:
            text = deal_datetime(text)
            year, month, date = text.split('/')
            header_div = div.find_element_by_attribute('css selector', 'div.bui-calendar-header',
                                                       timeout=self.timeout)
            yearmonth_switch = header_div.find_element_by_attribute(
                'css selector', 'div.month-text-container>span:nth-child(1)', timeout=self.timeout)
            yearmonth_switch.secure_click()
            yearmonth_div = div.find_element_by_attribute('css selector', 'div.bui-monthpicker',
                                                          timeout=self.timeout)
            # 设置year
            year_div = yearmonth_div.find_element_by_attribute(
                'css selector', 'div.bui-calendar-year-panel', timeout=self.timeout)
            self.__set_year(year_div, year)
            # 设置month
            month_div = yearmonth_div.find_element_by_attribute(
                'css selector', 'div.bui-calendar-month-panel', timeout=self.timeout)
            self.__set_month(month_div, month)
            confirm_switch = yearmonth_div.find_element_by_attribute(
                'css selector', 'ul.x-monthpicker-footer>li.bui-bar-item-button>button',
                'text:确定', timeout=self.timeout)
            confirm_switch.secure_click()
            # 设置date
            date_div = div.find_element_by_attribute('css selector', 'div.bui-calendar-panel',
                                                     timeout=self.timeout)
            self.__set_date(date_div, date)

    def set_value_for_time(self, div: WebElement, text):
        re_visible = r'visibility:\s*visible;'
        # 将日期与时间分离
        textlist = text.split(' ')
        all_date = textlist[0]
        all_date = deal_datetime(all_date)
        year, month, date = all_date.split('/')
        time = textlist[1]
        time = deal_time(time)
        hour, minute, second = time.split(':')
        # 选择日期
        header_div = div.find_element_by_attribute('css selector', 'div.bui-calendar-header',
                                                   timeout=self.timeout)
        yearmonth_switch = header_div.find_element_by_attribute(
            'css selector', 'div.month-text-container>span:nth-child(1)', timeout=self.timeout)
        yearmonth_switch.secure_click()
        yearmonth_div = div.find_element_by_attribute('css selector', 'div.bui-monthpicker',
                                                      timeout=self.timeout)
        # 设置year
        year_div = yearmonth_div.find_element_by_attribute(
            'css selector', 'div.bui-calendar-year-panel', timeout=self.timeout)
        self.__set_year(year_div, year)
        # 设置month
        month_div = yearmonth_div.find_element_by_attribute(
            'css selector', 'div.bui-calendar-month-panel', timeout=self.timeout)
        self.__set_month(month_div, month)
        confirm_switch = yearmonth_div.find_element_by_attribute(
            'css selector', 'ul.x-monthpicker-footer>li.bui-bar-item-button>button',
            'text:确定', timeout=self.timeout)
        confirm_switch.secure_click()
        # 设置date
        date_div = div.find_element_by_attribute('css selector', 'div.bui-calendar-panel',
                                                 timeout=self.timeout)
        self.__set_date(date_div, date)
        # 填写时间
        foot_ul = div.find_element_by_attribute('css selector', 'ul.bui-calendar-footer',
                                                timeout=self.timeout)
        time_li = foot_ul.find_element_by_attribute('xpath', './li[1]', timeout=self.timeout)
        # 设置hour
        time_li.find_element_by_attribute('xpath', './input[1]', timeout=self.timeout).secure_click()
        time_div = self.driver.find_element_by_attribute(
            'css selector', 'div.bui-list-picker.x-timepicker', 'style:' + re_visible,
            timeout=self.timeout)
        self.__set_time(time_div, hour)
        # 设置minute
        time_li.find_element_by_attribute('xpath', './input[2]', timeout=self.timeout).secure_click()
        time_div = self.driver.find_element_by_attribute(
            'css selector', 'div.bui-list-picker.x-timepicker', 'style:' + re_visible,
            timeout=self.timeout)
        self.__set_time(time_div, minute)
        # 设置second
        time_li.find_element_by_attribute('xpath', './input[3]', timeout=self.timeout).secure_click()
        time_div = self.driver.find_element_by_attribute(
            'css selector', 'div.bui-list-picker.x-timepicker', 'style:' + re_visible,
            timeout=self.timeout)
        self.__set_time(time_div, second)
        # 确定日历时间选择
        button = foot_ul.find_element_by_attribute('tag name', 'button', 'text:确定',
                                                   timeout=self.timeout)
        button.secure_click()

    def __set_year(self, year_div: WebElement, year):
        sleep(0.5)
        year_lis = year_div.find_elements_by_attribute(
            'css selector', 'ul>li.x-monthpicker-year', timeout=self.timeout)
        year_min = int(year_lis[0].text)
        year_max = int(year_lis[-1].text)
        if int(year) < year_min:
            prev_span = year_div.find_element_by_attribute(
                'css selector', 'div.x-monthpicker-yearnav>span.x-monthpicker-yearnav-prev',
                timeout=self.timeout)
            prev_span.secure_click()
            self.__set_year(year_div, year)
        elif int(year) > year_max:
            next_span = year_div.find_element_by_attribute(
                'css selector', 'div.x-monthpicker-yearnav>span.x-monthpicker-yearnav-next',
                timeout=self.timeout)
            next_span.secure_click()
            self.__set_year(year_div, year)
        else:
            for li in year_lis:
                if int(year) == int(li.text):
                    li.find_element_by_attribute('link text', year,
                                                 timeout=self.timeout).secure_click()
                    break

    def __set_month(self, month_div: WebElement, month):
        month_lis = month_div.find_elements_by_attribute(
            'css selector', 'ul>li.x-monthpicker-month', timeout=self.timeout)
        month_li = month_lis[int(int(month) - 1)].find_element_by_attribute(
            'tag name', 'a', timeout=self.timeout)
        month_li.secure_click()

    def __set_date(self, date_div: WebElement, date):
        date_tds = date_div.find_elements_by_attribute('css selector', 'td.x-datepicker-active',
                                                       timeout=self.timeout)
        for td in date_tds:
            if int(date) == int(td.text.strip()):
                td.find_element_by_attribute('tag name', 'a', timeout=self.timeout).secure_click()
                break

    def __set_time(self, time_div: WebElement, time):
        upul = time_div.find_element_by_attribute('css selector', 'div.bui-simple-list>ul',
                                                  timeout=self.timeout)
        time_lis = upul.find_elements_by_attribute('css selector', 'li.bui-list-item',
                                                   timeout=self.timeout)
        for li in time_lis:
            if int(time) == int(li.text.strip()):
                li.find_element_by_attribute('xpath', './a',
                                             timeout=self.timeout).secure_click()
                break

    def is_default(self, inputele: WebElement, value):
        """
        bui的日历控件默认值校验

        :Args:
         - inputele: 日历控件
         - value: 校验值

        :Returns:
            正确返回True，校验不匹配则返回False
        """
        if inputele.text:
            text = inputele.text
        elif inputele.get_attribute('value'):
            text = inputele.get_attribute('value')
        elif inputele.get_attribute('placeholder'):
            text = inputele.get_attribute('placeholder')
        elif inputele.get_attribute('title'):
            text = inputele.get_attribute('title')
        else:
            text = ''
        if text.strip() == value.strip():
            return True
        else:
            raise SeleniumError("默认值比匹配：期待的默认值为：{}; 实际的默认值为：{}".format(value, text))

    def is_default_for_group(self, inputs, value):
        """
        bui的日历控件组默认值校验

        :Args:
         - inputs: 日历控件组
         - value: 校验值

        :Returns:
            正确返回True，校验不匹配则返回False
        """
        value1 = value[0]
        if len(value) < 2:
            value2 = value[0]
        else:
            value2 = value[1]
        textlist = list()
        for inputele in inputs:
            if inputele.text:
                textlist.append(inputele.text)
            elif inputele.get_attribute('value'):
                textlist.append(inputele.get_attribute('value'))
            elif inputele.get_attribute('placeholder'):
                textlist.append(inputele.get_attribute('placeholder'))
            elif inputele.get_attribute('title'):
                textlist.append(inputele.get_attribute('title'))
            else:
                textlist.append('')
        if textlist[0].strip() == value1.strip() and textlist[1].strip() == value2.strip():
            return True
        else:
            raise SeleniumError("默认值比匹配：期待的默认值1为：{}; "
                                "实际的默认值1为：{}, 期待的默认值2为："
                                "{}; 实际的默认值2为：{}".format(value1, textlist[0],
                                                         value2, textlist[1]))

class TextType(BaseElement):
    '''bui的文本框操作'''

    def __init__(self, element_para, father=None, timeout=5):
        if element_para:
            super().__init__(element_para, father, timeout)
        else:
            self.driver = father
            self.timeout = timeout

    def is_default(self, value):
        """
        bui的文本框默认值校验

        :Args:
         - inputele: 文本框控件
         - value: 校验值

        :Returns:
            正确返回True，校验不匹配则返回False
        """
        if self.element.text:
            text = self.element.text
        elif self.element.get_attribute('value'):
            text = self.element.get_attribute('value')
        elif self.element.get_attribute('placeholder'):
            text = self.element.get_attribute('placeholder')
        elif self.element.get_attribute('title'):
            text = self.element.get_attribute('title')
        else:
            text = ""
        if text.strip() == value.strip():
            return True
        else:
            # logger.error('默认值不匹配！')
            raise SeleniumError("默认值比匹配：期待的默认值为：{}; 实际的默认值为：{}".format(value, text))

    def is_default_for_group(self, inputs, value):
        """
        bui的文本框组默认值校验

        :Args:
         - inputs: 文本框控件组
         - value: 校验值

        :Returns:
            正确返回True，校验不匹配则返回False
        """
        value1 = value[0]
        if len(value) < 2:
            value2 = value[0]
        else:
            value2 = value[1]
        textlist = list()
        for inputele in inputs:
            if inputele.text:
                textlist.append(inputele.text)
            elif inputele.get_attribute('value'):
                textlist.append(inputele.get_attribute('value'))
            elif inputele.get_attribute('placeholder'):
                textlist.append(inputele.get_attribute('placeholder'))
            elif inputele.get_attribute('title'):
                textlist.append(inputele.get_attribute('title'))
            else:
                textlist.append('')
        if textlist[0].strip() == value1.strip() and textlist[1].strip() == value2.strip():
            return True
        else:
            # logger.error('默认值不匹配！')
            raise SeleniumError("默认值比匹配：期待的默认值1为：{}; 实际的默认值1为：{}, 期待的默认值2为：{}; 实际的默认值2为：{}".format(value1, textlist[0],value2, textlist[1]))

    def set_value(self, value):
        '''
        文本框填充

        :Args:
         - text: 填充值
        '''
        # input_element.focus()
        # input_element.clear()
        # input_element.send_keys(value)
        self.element.focus()
        self.element.clear()
        self.element.send_keys(value)

    def is_readonly(self):
        '''
        检查文本框是否只读

        :Return:
            返回文本框是否只读
        '''
        self.element.focus()
        return self.element.is_readonly()

    def clear(self):
        '''
        文本框清空
        '''
        self.element.focus()
        self.element.clear()

class Radio(PublicUI):
    '''bui的单选按钮操作'''

    def set_value(self, inputs, text):
        '''
        bui的单选按钮赋值

        :Args:
         - inputs: 单选按钮控件组
         - text: 选项
        '''
        for inputele in inputs:
            radio_label = inputele.find_element_by_attribute('xpath', './parent::*',
                                                             timeout=self.timeout)
            radio_text = radio_label.text.strip()
            if text == radio_text:
                inputele.secure_click()
                break

    def is_default(self, inputs, text):
        '''
        bui的单选按钮默认值校验

        :Args:
         - inputs: 单选按钮控件组
         - text: 校验值

        :Returns:
            正确返回True，校验不匹配则返回False
        '''
        for inputele in inputs:
            status = inputele.get_attribute('checked')
            if status:
                radio_text = inputele.find_element_by_attribute('xpath:./parent::*',
                                                                timeout=self.timeout).text
                if text == radio_text:
                    return True
        else:
            raise SeleniumError("默认值比匹配：期待的默认值为：{}; 实际的默认值为：{}".format(value, text))

class Checkbox(PublicUI):
    '''bui的复选框操作'''

    def set_value(self, inputs, textlist):
        '''
        bui的复选框赋值

        :Args:
         - inputs: 复选框控件组
         - textlist: 选项列表
        '''
        # 排除非复选框元素和不显示的复选框
        i = 0
        labels = list()
        while i < len(inputs):
            if 'checkbox' in inputs[i].get_attribute('type'):
                try:
                    label = inputs[i].find_element_by_attribute('xpath', './parent::label',
                                                                timeout=self.timeout)
                except NoDisplayError:
                    inputs.remove(inputs[i])
                else:
                    labels.append(label)
                    i += 1
            else:
                inputs.remove(inputs[i])
        # 获取当前已选中的value
        input_hidden = inputs[0].find_elements_by_attribute(
            'xpath', './parent::label/preceding-sibling::input[@type="hidden"]',
            timeout=self.timeout)[0]
        values = input_hidden.get_attribute('value').split(',')
        # 获取input对应的value
        inputs_value = list()
        for inputele in inputs:
            inputele_value = inputele.get_attribute('value').strip()
            inputs_value.append(inputele_value)
        # 选择前先全部清空
        for i in range(0, len(inputs)):
            if inputs_value[i] in values:
                inputs[i].secure_click()
        # 进行选择
        if textlist[0] == 'all':
            for i in range(0, len(inputs)):
                inputs[i].secure_click()
        else:
            for text in textlist:
                for i in range(0, len(inputs)):
                    chkbox_text = labels[i].text.strip()
                    if text == chkbox_text:
                        inputs[i].secure_click()
                        break
                else:
                    logger.warn('未选中选项：' + text)

    def is_default(self, inputs, value):
        '''
        bui的复选框默认值校验

        :Args:
         - inputs: 复选框控件组
         - text: 校验值

        :Returns:
            正确返回True，校验不匹配则返回False
        '''
        # 排除非复选框元素和不显示的复选框
        i = 0
        labels = list()
        while i < len(inputs):
            if 'checkbox' in inputs[i].get_attribute('type'):
                try:
                    label = inputs[i].find_element_by_attribute('xpath:./parent::label',
                                                                timeout=self.timeout)
                except NoDisplayError:
                    inputs.remove(inputs[i])
                else:
                    labels.append(label)
                    i += 1
            else:
                inputs.remove(inputs[i])
        # 获取当前已选中的value
        input_hidden = inputs[0].find_elements_by_attribute(
            'xpath:./parent::label/preceding-sibling::input[@type="hidden"]',
            timeout=self.timeout)[0]
        values = input_hidden.get_attribute('value').split(',')
        # 获取input对应的value
        inputs_value = list()
        for inputele in inputs:
            inputele_value = inputele.get_attribute('value').strip()
            inputs_value.append(inputele_value)
        # 挑选出选中的checkbox
        x = 0
        while x < len(inputs):
            if inputs_value[x] in values:
                x += 1
            else:
                inputs.remove(inputs[x])
        for text in value:
            j = 0
            for i in range(0, len(inputs)):
                chkbox_text = labels[i].text.strip()
                if chkbox_text == text:
                    j += 1
            if j < 1:
                raise SeleniumError("默认值比匹配：期待的默认值为：{}; 实际的默认值为：{}".format(text, chkbox_text))
        else:
            return True